import React, { createContext, useCallback, useEffect, useReducer } from 'react';
import { IProps, IViewer, IContext, IContextState } from './interface';
import ScreenshotsCanvas from './ScreenshotsCanvas';
import { reducer, inital } from './ScreenshotsContext';
import ScreenshotsMagnifier from './ScreenshotsMagnifier';
import ScreenshotsViewer from './ScreenshotsViewer';

export const ScreenshotsContext = createContext<IContext>({ state: inital, dispatch: reducer });
export default (props: IProps) => {
    const { width, height, image } = props;
    const classNames = ['screenshots'];
    if (props.className) classNames.push(props.className);
    const bodyRef = React.useRef<HTMLDivElement>(null);

    const [state, dispatch] = useReducer(reducer, inital) as [IContextState, any];

    const updateViewer = ({ x1, y1, x2, y2 }: IViewer) => {
        if (!state.viewer) return;
        const { viewer } = state;
        const x = x1;
        const y = x2;
        // 交换值
        if (x1 > x2) {
            x1 = x2;
            x2 = x;
        }

        if (y1 > y2) {
            y1 = y2;
            y2 = y;
        }

        // 把图形限制在元素里面
        if (x1 < 0) {
            x1 = 0;
            x2 = viewer.x2;
        }

        if (x2 > width) {
            x2 = width;
            x1 = viewer.x1;
        }
        if (y1 < 0) {
            y1 = 0;
            y2 = viewer.y2;
        }

        if (y2 > height) {
            y2 = height;
            y1 = viewer.y1;
        }
        dispatch({
            type: 'setViewer',
            data: viewer,
        });
    };
    
    const onViewerChange = (options: IViewer) => {
        updateViewer(options);
    };
    
    /** 初始化width, image */
    useEffect(() => {
        if (!image) return
        dispatch({
            type: 'init',
            data: {
                width,
                height,
                image 
            },
        });
    }, [dispatch, width, height, image]);

    const onMagnify = useCallback(({ x, y }: { x: number; y: number }) => {
        if (!bodyRef.current) return;
        const { left, top, width, height } = bodyRef.current.getBoundingClientRect();
        if (x >= left && x <= left + width && y >= top && y <= top + height) {
            dispatch({
                type: 'setMagnifyPoint',
                data: {
                    x: x - left,
                    y: y - top,
                    right: left + width,
                    bottom: top + height,
                },
            });
        }
    }, [dispatch]);

    const onCanvasChange = useCallback(({ x1, y1, x2, y2 }) => {
        if (!bodyRef.current) return
        const { left, top } = bodyRef.current.getBoundingClientRect()
        x1 = x1 - left
        y1 = y1 - top
        x2 = x2 - left
        y2 = y2 - top
        dispatch({
            type: 'setViewer',
            data: { x1, y1, x2, y2 }
        })
    }, [dispatch]);

    return (
        <ScreenshotsContext.Provider
            value={{
                state,
                dispatch,
            }}
        >
            <div className={classNames.join(' ')} style={{ width, height }} ref={bodyRef}>
                <ScreenshotsCanvas onMagnify={onMagnify} onChange={onCanvasChange} />
                {!state.viewer || (state.viewer && state.viewer.resizing) ? <ScreenshotsMagnifier /> : null}
                <ScreenshotsViewer onChange={onViewerChange} />
            </div>
        </ScreenshotsContext.Provider>
    );
};
